package gupao.concurrency.lock;

import gupao.concurrency.lock.utils.Utils;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class SimpleLiveLockSample {

    static Lock lock0 = new ReentrantLock();
    static Lock lock1 = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Thread t0 = new Thread(() -> {
            try{
                process0();
            }catch (Exception e){
                //ignore
            }
        }, "t0");

        Thread t1 = new Thread(() -> {
            try{
                process1();
            }catch (Exception e){
                //ignore
            }
        }, "t1");

        t0.start();
        t1.start();
        t0.join();
        t1.join();
    }

    public static void process0() throws InterruptedException {
        while(true){
            boolean fail = false;
            if(lock0.tryLock(500, TimeUnit.MILLISECONDS)){
                try{
                    log.info("lock0 is acquired, try to acquire lock1..");
                    Utils.sleepIgnoreExp(500);
                    if(lock1.tryLock()){
                        try{
                            log.info("lock1 is acquired.");
                            log.info("do process0...");
                        }finally {
                            lock1.lock();
                        }
                    } else {
                        fail = true;
                        log.info("lock0 is acquired, lock1 is failed. Unlock all locks and continue");
                    }
                }finally {
                    lock0.unlock();
                }
            }
            if(fail){
                Utils.sleepIgnoreExp(new Random().nextInt(1000) + 10);
            }
        }
    }

    public static void process1() throws InterruptedException {
        while(true){
            boolean fail = false;
            if(lock1.tryLock(500, TimeUnit.MILLISECONDS)){
                try{
                    log.info("lock1 is acquired, try to acquire lock0..");
                    Utils.sleepIgnoreExp(500);
                    if(lock0.tryLock()){
                        try{
                            log.info("lock0 is acquired.");
                            log.info("do process1...");
                        }finally {
                            lock0.lock();
                        }
                    } else {
                        fail = true;
                        log.info("lock1 is acquired, lock0 is failed. Unlock all locks and continue");
                    }
                }finally {
                    lock1.unlock();
                }
            }
            if(fail){
                Utils.sleepIgnoreExp(new Random().nextInt(1000) + 10);
            }
        }
    }
}
